
---@class UIComponentInterface
UIComponentInterface = Class("UIComponentInterface")
local _M = UIComponentInterface

-- 重写table的赋值行为
_M.__newindex = function(t,key,value)
    rawset(t,key,value)
    if key == nil or value == nil then
        return
    end
    if key == "_index" or key == "__newindex" then
        return
    end
    
    if t.AddReference and t.IsDelReference then 
        if t:IsDelReference(key,value) or type(value) == "table" then 
            t:AddReference(key,value)
        end
    end
end

--- 存储C#引用 销毁时自动清理
--- 1 清理Table：self.cusTable = {}
--- 2 清理直接对象 self.obj = self:GetChild("")
_M.autoDeleteReference = nil
function _M:AddReference(name,ref)
    if self.autoDeleteReference == nil then
        rawset(self,"autoDeleteReference",{})
    end
    self.autoDeleteReference[name] = ref
end
function _M:DelReference(name)
    if self.autoDeleteReference == nil then
        return
    end
    local obj = self.autoDeleteReference[name]
    if type(obj) == "table" then
        self:DelReferenceTable(obj,5)    -- 最多检测5层嵌套table 为了效率
    else
        self:DelReferenceValue(self,name,obj)
    end
end
function _M:DelReferenceValue(table,key,value)
    if self:IsDelReference(key,value) then
        rawset(table,key,nil)
    end
end
function _M:DelReferenceTable(table,checkLayer)
    for key, value in pairs(table) do
        if type(value) == "table" then
            checkLayer = checkLayer - 1
            if checkLayer < 0 then
                break
            end
            self:DelReferenceTable(value,checkLayer)
        end
        self:DelReferenceValue(table,key,value)
    end
end
function _M:DelReferenceAll()
    self:RemoveAllTimeCall()
    self:UnRegisterBehaviourClick()

    self.hasInit = false
    if self.autoDeleteReference == nil then
        return
    end
    for key, value in pairs(self.autoDeleteReference) do
        self:DelReference(key)
    end
    self.autoDeleteReference = nil

end
function _M:IsDelReference(obj1,obj2)
    return type(obj1) == "userdata" or type(obj2) == "userdata"
end
function _M:OnDestroyAfter()
    self:DelReferenceAll()
end
--region 控件获取
--- FGUI
---@return GComponent
function _M:GetChild(path,root)
    local spPath = ""
    local obj
    if string.find(path,"/") then
        local list = TablePool.Get()
        string_split(path,"/",list)
        obj = root and root:GetChild(list[1]) or self.fguiObj:GetChild(list[1])
        for i = 2, #list do
            if obj then
                obj = obj:GetChild(list[i])
            end
        end
        TablePool.Release(list)
    else
        spPath = path
        obj = root and root:GetChild(spPath) or self.fguiObj:GetChild(spPath)
    end

    if obj == nil then
        local obj = root or self.fguiObj
        logError("GetChild is nil ," ..tostring(path).." "..obj.name)
    end
    return obj
end
---@return GList
function _M:GetList(path,root)
    return self:GetChild(path,root)
end
---@return GController
function _M:GetController(path,root)
    return root and root:GetController(path) or self.fguiObj:GetController(path)
end
---@return FairyGUI.Transition
function _M:GetTransition(name,root)
    if string.IsEmpty(name) then return nil end
    return root and root:GetTransition(name) or self.fguiObj:GetTransition(name)
end
--endregion 控件获取
--region UI控件内容设置
---@param itemCall fun(tb:table,index:number,go:GComponent) 注意：index已经从1开始了
---@param tb table 调onCall的对象，或者不传，自动传隐式self
function _M:SetItemRenderer(dynamicList,itemCall,tb,notVirtual)
    if not dynamicList then return end
    dynamicList.itemRenderer = function(index, itemobj)itemCall(tb or self,index+1, itemobj)end
    if notVirtual == nil or notVirtual == false then
        dynamicList:SetVirtual()
    end
    return dynamicList
end


--endregion UI控件内容设置
--region 定时器处理
---@param interval number 多少[毫秒]执行一次
---@param  callback  fun():boolean   定时完成后的回调函数，如果在回调中返回true，可停用此定时器
---@param times number 定时次数，默认为1，-1为无限制
---@param params any 自定义参数，原样返回
function _M:TimeCall(callback, interval, times,params)
    if not callback then return end
    self:RemoveTimeCall(callback)
    interval = interval/1000
    local id = UTimer.TimeCall(function()
            return callback(self, params)
        end,nil,interval,times or 1)
    if not self._timeCallReferenceList then
        self._timeCallReferenceList = {}
    end
    self._timeCallReferenceList[id] = callback
    return id
end
function _M:RemoveTimeCall(callback)
    if not self._timeCallReferenceList then
        return
    end
    for k,v in pairs(self._timeCallReferenceList) do
        if v == callback then
            self._timeCallReferenceList[k] = nil
            UTimer.Remove(k)
            return
        end
    end
end
function _M:RemoveAllTimeCall()
    if not self._timeCallReferenceList then
        return
    end
    for k,v in pairs(self._timeCallReferenceList) do
        UTimer.Remove(k)
    end
    self._timeCallReferenceList = nil
end
--endregion 定时器处理
--region 注册BehaviourEvent

---@param params any 自定义参数,原样返回
---@param go GObject
---@param tb table 调onCall的对象，或者不传，自动传隐式self
function _M:RegisterOnClick(go,onCall,tb,params)
    self:_RegisterClick("onClick",go,onCall,tb,params)
end
function _M:RegisterTouchBegin(go,onCall,tb)
    self:_RegisterClick("onTouchBegin",go,onCall,tb)
end
function _M:RegisterTouchMove(go,onCall,tb)
    self:_RegisterClick("onTouchMove",go,onCall,tb)
end
function _M:RegisterTouchEnd(go,onCall,tb)
    self:_RegisterClick("onTouchEnd",go,onCall,tb)
end
function _M:RegisterDragStart(go,onCall,tb)
    self:_RegisterClick("onDragStart",go,onCall,tb)
end
function _M:RegisterDragMove(go,onCall,tb)
    self:_RegisterClick("onDragMove",go,onCall,tb)
end
function _M:RegisterDragEnd(go,onCall,tb)
    self:_RegisterClick("onDragEnd",go,onCall,tb)
end
function _M:RegisterOnChanged(go,onCall,tb)
    self:_RegisterClick("onChanged",go,onCall,tb)
end
---@private
function _M:_RegisterClick(name,go,onCall,tb,params)
    if go == nil or onCall == nil then
        return
    end
    if params then
        go[name]:Add(function()
            onCall(tb or self,params)
        end)
    else
        go[name]:Add(onCall,tb or self)
    end
    if self._behaviourEvent == nil then
        rawset(self,"_behaviourEvent",{})
    end
    table.insert(self._behaviourEvent,{go = go,evt = name})
end
-- 卸载BehaviourEvent
---@private
function _M:UnRegisterBehaviourClick()
    if self._behaviourEvent == nil then
        return
    end
    for key, value in pairs(self._behaviourEvent) do
        if value.go and value.evt then value.go[value.evt]:Clear() end
    end
    self._behaviourEvent = nil
end
function _M:TryRegisterOnClick(go,onCall)
    local name = "onClick"
    for _, value in pairs(self._behaviourEvent) do
        if value.go and value.go == go and value.evt then 
            go[name]:Add(onCall,self)
            return
        end
    end
    self:_RegisterClick(name,go,onCall)
end
--endregion 注册BehaviourEvent